@page "/admin/roles"
@using BlazorBoilerplate.Shared.Dto.Admin
@attribute [Authorize]
@inject HttpClient Http
@inject IAuthorizationService AuthorizationService
@inject AuthenticationStateProvider authStateProvider
@inject IMatToaster matToaster
@inject AppState appState

@using Newtonsoft.Json;
@using System.Net

<h1>Roles</h1>
<p>Roles Management.</p>

@if (roles == null)
{
    <LoadingBackground ShowLogoBox="true">
        <label>Loading Roles</label>
    </LoadingBackground>
}
else
{
    <MatTable Class="mat-elevation-z5" Items="@roles" LoadInitialData="true" Striped="true" RequestApiOnlyOnce="true" ApiUrl="api/roles"
              DebounceMilliseconds="150">
        <MatTableHeader>
            <th><MatButton Icon="add" Label="New Role" OnClick="@(() => OpenUpsertRoleDialog())"></MatButton></th>
            <th>Name</th>
            <th>Permissions</th>
        </MatTableHeader>
        <MatTableRow Context="RoleRow">
            <td>
                <div style="width:155px;">
                    <MatIconButton Icon="edit" OnClick="@(() => OpenUpsertRoleDialog(@RoleRow.Name))"></MatIconButton>
                    <MatIconButton Icon="delete" OnClick="@(() => OpenDeleteDialog(@RoleRow.Name))"></MatIconButton>
                </div>
            </td>
            <td><div style="width:130px;">@RoleRow.Name</div></td>
            <td>
                <MatChipSet>
                    @foreach (var permission in @RoleRow.Permissions)
                        {
                        <MatChip Label="@permission"></MatChip>
                        }
                </MatChipSet>
            </td>
        </MatTableRow>
    </MatTable>
}

<MatDialog @bind-IsOpen="@isUpsertRoleDialogOpen">
    <MatDialogTitle>
        @labelUpsertDialogTitle
    </MatDialogTitle>
    <MatDialogContent>
        <fieldset>
            <div class="form-group">
                <MatTextField @bind-Value="@currentRoleName" Disabled="@isCurrentRoleReadOnly" Label="Role Name" Icon="add" IconTrailing="true" FullWidth="true" Required="true"></MatTextField>
            </div>
        </fieldset>

        <MatTable Items="@permissionsSelections" Class="mat-elevation-z5" ShowPaging="false">
            <MatTableHeader>
                <th>Permissions</th>
                <th>Allow</th>
            </MatTableHeader>
            <MatTableRow>
                <td>@context.Name</td>
                <td><MatCheckbox TValue="bool" @bind-Value="@context.IsSelected"></MatCheckbox></td>
            </MatTableRow>
        </MatTable>

    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@(e => { isUpsertRoleDialogOpen = false; })">Cancel</MatButton>
        <MatButton OnClick="@UpsertRole">@labelUpsertDialogOkButton</MatButton>
    </MatDialogActions>
</MatDialog>

<MatDialog @bind-IsOpen="@isDeleteRoleDialogOpen" Style="z-index:100">
    <MatDialogTitle><MatIcon Icon="warning"></MatIcon> Confirm Delete</MatDialogTitle>
    <MatDialogContent>
        Are you sure you want to delete the role "@currentRoleName" ?
    </MatDialogContent>
    <MatDialogActions>
        <MatButton OnClick="@(e => { isDeleteRoleDialogOpen = false; })">Cancel</MatButton>
        <MatButton OnClick="@DeleteRoleAsync">Delete</MatButton>
    </MatDialogActions>
</MatDialog>

@code {
    int pageSize { get; set; } = 15;
    int currentPage { get; set; } = 0;

    string currentRoleName = "";
    bool isCurrentRoleReadOnly = false;

    List<RoleDto> roles;

    #region OnInitializedAsync

    protected override async Task OnInitializedAsync()
    {
        await InitializeRolesListAsync();
    }

    public async Task InitializeRolesListAsync()
    {
        try
        {
            var apiResponse = await Http.GetFromJsonAsync<ApiResponseDto<List<RoleDto>>>($"api/Admin/Roles?pageSize={pageSize}&pageNumber={currentPage}");

            if (apiResponse.IsSuccessStatusCode)
            {
                matToaster.Add(apiResponse.Message, MatToastType.Success, "Roles Retrieved");
                roles = apiResponse.Result;
            }
            else
                matToaster.Add(apiResponse.Message + " : " + apiResponse.StatusCode, MatToastType.Danger, "Roles Retrieval Failed");
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.GetBaseException().Message, MatToastType.Danger, "Roles Retrieval Error");
        }
    }

    #endregion

    #region OpenUpsertRoleDialog

    bool isUpsertRoleDialogOpen = false;
    bool isInsertOperation;
    List<PermissionSelection> permissionsSelections = new List<PermissionSelection>();

    string labelUpsertDialogTitle;
    string labelUpsertDialogOkButton;

    public class PermissionSelection
    {
        public bool IsSelected { get; set; }
        public string Name { get; set; }
    };

    public async Task OpenUpsertRoleDialog(string roleName = "")
    {
        try
        {
            currentRoleName = roleName;

            isInsertOperation = string.IsNullOrWhiteSpace(roleName);

            // Update the UI
            if (isInsertOperation)
            {
                labelUpsertDialogTitle = "Create Role";
                labelUpsertDialogOkButton = "Create Role";
            }
            else
            {
                labelUpsertDialogTitle = "Edit Role";
                labelUpsertDialogOkButton = "Update Role";
            }

            // Retrieve the role
            RoleDto role = null;
            isCurrentRoleReadOnly = !isInsertOperation;

            if (isCurrentRoleReadOnly)
            {
                var roleResponse = await Http.GetFromJsonAsync<ApiResponseDto<RoleDto>>($"api/Admin/Role/{roleName}");
                role = roleResponse.Result;
            }

            // Setup the permissions
            var response = await Http.GetFromJsonAsync<ApiResponseDto<List<string>>>("api/Admin/Permissions");
            permissionsSelections.Clear();


            foreach (var name in response.Result)
            {
                permissionsSelections.Add(new PermissionSelection
                {
                    Name = name,
                    IsSelected = (role == null) ? false : role.Permissions.Contains(name)
                });
            }

            isUpsertRoleDialogOpen = true;
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.GetBaseException().Message, MatToastType.Danger, $"{labelUpsertDialogTitle} Error");
        }
    }

    public async Task UpsertRole()
    {
        try
        {
            if (string.IsNullOrWhiteSpace(currentRoleName))
            {
                matToaster.Add("Role Creation Error", MatToastType.Danger, "Enter in a Role Name");
                return;
            }

            RoleDto request = new RoleDto
            {
                Name = currentRoleName,
                Permissions = new List<string>()
            };

            foreach (var status in permissionsSelections)
                if (status.IsSelected)
                    request.Permissions.Add(status.Name);

            ApiResponseDto apiResponse;

            if (isInsertOperation)
            {
                HttpResponseMessage response = await Http.PostAsJsonAsync("api/Admin/Role", request);
                apiResponse = JsonConvert.DeserializeObject<ApiResponseDto>(await response.Content.ReadAsStringAsync());
            }
            else
            {
                HttpResponseMessage response = await Http.PutAsJsonAsync("api/Admin/Role", request);
                apiResponse = JsonConvert.DeserializeObject<ApiResponseDto>(await response.Content.ReadAsStringAsync());
            }

            if (apiResponse.IsSuccessStatusCode)
            {
                matToaster.Add(isInsertOperation ? "Role Created" : "Role Updated", MatToastType.Success);

                //await PopulateRoleList();
                StateHasChanged();
            }
            else
                matToaster.Add(apiResponse.Message, MatToastType.Danger);


            // this.StateHasChanged();
            await OnInitializedAsync();

            isUpsertRoleDialogOpen = false;
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.GetBaseException().Message, MatToastType.Danger, "Role Operation Error");
        }
    }

    #endregion

    #region OpenDeleteDialog

    bool isDeleteRoleDialogOpen = false;

    public void OpenDeleteDialog(string roleName)
    {
        currentRoleName = roleName;
        isDeleteRoleDialogOpen = true;
    }

    public async Task DeleteRoleAsync()
    {
        try
        {
            var response = await Http.DeleteAsync($"api/Admin/Role/{currentRoleName}");
            if (response.StatusCode != (HttpStatusCode)Status200OK)
            {
                matToaster.Add("Role Delete Failed", MatToastType.Danger);
                return;
            }

            matToaster.Add("Role Deleted", MatToastType.Success);
            await OnInitializedAsync();
            isDeleteRoleDialogOpen = false;
            StateHasChanged();
        }
        catch (Exception ex)
        {
            matToaster.Add(ex.GetBaseException().Message, MatToastType.Danger, "Role Delete Error");
        }
    }

    #endregion

}
